<template>
  <div class="containers" ref="content">
    <IndexTitle />
    <div class="canvas" ref="canvas"></div>
    <PropertiesView
      v-if="CurrentElement.type in ElementType"
      :form_id.sync="Form[CurrentElement.id]"
      :key="CurrentElement.id"
      @keysChanged="updateRelatedSequenceFlow"
    />
    <ul class="buttons">
      <li>下载</li>
      <li>
        <a ref="saveDiagram" href="javascript:" title="download BPMN diagram">BPMN diagram</a>
      </li>
      <li>
        <a ref="saveSvg" href="javascript:" title="download as SVG image">SVG image</a>
      </li>
      <li>
        <a>
          <input type="text" v-model="apiPath" />
        </a>
        <a @click="newTask" class="active" title="create new task">New Task</a>
      </li>
      <li>
        <a @click="updateProcess" class="active">refresh</a>
      </li>
      <li>
        <a @click="submit" class="active">submit</a>
      </li>
    </ul>
  </div>
</template>

<script>
import BpmnModeler from "bpmn-js/lib/Modeler";
import propertiesProviderModule from "bpmn-js-properties-panel/lib/provider/camunda";
import BpmnModdle from "bpmn-moddle";
import global_ from "./Global";
import IndexTitle from "./IndexTitle";
import PropertiesView from "./PropertiesView.vue";

export default {
  data() {
    return {
      // bpmn建模器
      bpmnModeler: null,
      container: null,
      canvas: null,
      xmlStr: null,
      processName: "",
      bpmnXmlStr: "",
      CurrentElement: {
        id: "",
        name: "",
        type: ""
      },
      ElementType: {
        "bpmn:Task": "",
        "bpmn:SequenceFlow": "",
        "bpmn:StartEvent": "",
        "bpmn:EndEvent": "",
        Process: ""
      },
      TaskList: [],
      SequenceFlowList: [],
      StartEventId: "",
      EndEventId: "",
      apiPath: "/idcard",
      Form: {}
    };
  },
  components: {
    IndexTitle,
    PropertiesView
  },
  methods: {
    createNewDiagram() {
      this.bpmnXmlStr = global_.bpmnStr;
      // 将字符串转换成图显示出来
      this.bpmnModeler.importXML(this.bpmnXmlStr, function(err) {
        if (err) {
          console.error(err);
        }
      });
    },
    // 下载为SVG格式,done是个函数，调用的时候传入的
    saveSVG(done) {
      // 把传入的done再传给bpmn原型的saveSVG函数调用
      this.bpmnModeler.saveSVG(done);
    },
    // 下载为XML格式,done是个函数，调用的时候传入的
    saveDiagram(done) {
      // 把传入的done再传给bpmn原型的saveXML函数调用
      this.bpmnModeler.saveXML({ format: true }, function(err, xml) {
        done(err, xml);
      });
    },
    // 当图发生改变的时候会调用这个函数，这个data就是图的xml
    setEncoded(link, name, data) {
      // 把xml转换为URI，下载要用到的
      const encodedData = encodeURIComponent(data);
      // 获取到图的xml，保存就是把这个xml提交给后台
      this.xmlStr = data;
      // 下载图的具体操作,改变a的属性，className令a标签可点击，href令能下载，download是下载的文件的名字
      if (data) {
        link.className = "active";
        link.href = "data:application/bpmn20-xml;charset=UTF-8," + encodedData;
        link.download = name;
      }
    },
    newTask() {
      if (this.CurrentElement.id == null || this.CurrentElement.id == "") {
        alert(" No Task choosen! ");
      } else if (this.CurrentElement.type != "bpmn:Task") {
        alert("Please select a task!");
      } else {
        let _this = this;
        this.$http
          .get("http://192.168.9.49:8077/sc/comp/api/query.do?ApiPath=" + this.apiPath)
          .then(response => {
            var nt = response.data;
            if (nt.data) {
              console.log(nt.data);
              console.log(_this.CurrentElement.id);
              console.log(_this.Form);
              _this.$set(_this.Form, _this.CurrentElement.id, nt.data);
              _this.$set(
                _this.Form[_this.CurrentElement.id],
                "type",
                "bpmn:Task"
              );
              _this.updateTask(nt.data, _this.CurrentElement.id);
              console.log("after ut", _this.Form);
            } else {
              alert(nt.message);
            }
          });
        // .catch(err => {
        //   alert(err);
        // });
      }
    },
    updateTask(taskData, taskid) {
      var elementRegistry = this.bpmnModeler.get("elementRegistry");
      var taskElement = elementRegistry.get(taskid);
      if (taskElement.incoming != null) {
        console.log("incoming", taskElement.incoming);
        for (let i = 0; i < taskElement.incoming.length; ++i) {
          //处理前面的sequenceFlow
          let sequenceFlow = taskElement.incoming[i];
          console.log(sequenceFlow);
          let s = sequenceFlow.source.id;
          let t = sequenceFlow.target.id;
          if (!(sequenceFlow.id in this.Form)) {
            if (!(s in this.Form)) continue;
            this.Form[sequenceFlow.id] = {
              type: "bpmn:SequenceFlow",
              id: sequenceFlow.id,
              source: s,
              target: t,
              maps: {},
              values: this.Form[s].outputKeys
            };
            console.log("sequence1", this.Form[t]);
            this.Form[sequenceFlow.id].maps = {};
            let maps = {};
            for (let i = 0; i < this.Form[t].inputKeys.length; ++i)
              maps[this.Form[t].inputKeys[i]] = ["", ""];
            this.Form[sequenceFlow.id].maps = maps;
          } else {
            let t = sequenceFlow.target.id;
            console.log("sequence2", this.Form[t].inputKeys);
            let maps = {};
            for (let i = 0; i < this.Form[t].inputKeys.length; ++i)
              maps[this.Form[t].inputKeys[i]] = ["", ""];
            this.Form[sequenceFlow.id].maps = maps;
          }
        }
      }
      if (taskElement.outgoing != null) {
        console.log("outgoing", taskElement.outgoing);
        for (let i = 0; i < taskElement.outgoing.length; ++i) {
          //处理后面的sequenceFlow
          let sequenceFlow = taskElement.outgoing[i];
          console.log(sequenceFlow);
          let s = sequenceFlow.source.id;
          let t = sequenceFlow.target.id;
          if (!(t in this.Form)) continue;
          if (!(sequenceFlow.id in this.Form)) {
            this.Form[sequenceFlow.id] = {
              type: "bpmn:SequenceFlow",
              id: sequenceFlow.id,
              source: s,
              target: t,
              maps: {},
              values: this.Form[s].outputKeys
            };
            let maps = {};
            for (let i = 0; i < this.Form[t].inputKeys.length; ++i)
              maps[this.Form[t].inputKeys[i]] = ["", ""];
            this.Form[sequenceFlow.id].maps = maps;
            this.Form[sequenceFlow.id].values = this.Form[s].outputKeys;
            console.log("sequence3");
          } else {
            let maps = {};
            for (let i = 0; i < this.Form[t].inputKeys.length; ++i)
              maps[this.Form[t].inputKeys[i]] = ["", ""];
            this.Form[sequenceFlow.id].maps = maps;
            this.Form[sequenceFlow.id].values = this.Form[s].outputKeys;
            console.log("sequence4");
          }
        }
      }
      var modeling = this.bpmnModeler.get("modeling");
      console.log("Updated!");
      modeling.updateProperties(taskElement, {
        name: taskData.name
      });
    },
    updateProcess() {
      let elementRegistry = this.bpmnModeler.get("elementRegistry");
      let tasks_tmp = [];
      console.log(this.TaskList);
      for (let i = 0; i < this.TaskList.length; ++i) {
        let taskId = this.TaskList[i];
        let t = {
          name: this.Form[taskId].name,
          taskReferenceName: this.Form[taskId].description,
          type: "SIMPLE",
          inputParameters: {}
        };
        let taskElement = elementRegistry.get(taskId);
        if (taskElement.incoming != null) {
          for (let i = 0; i < taskElement.incoming.length; ++i) {
            //处理前面的sequenceFlow
            let sequenceFlow = taskElement.incoming[i];
            let pre = sequenceFlow.source.id;
            let inputCopy = Object.assign({}, this.Form[sequenceFlow.id].maps);
            for (let j in inputCopy) {
              if (inputCopy[j] != null && inputCopy[j][0] != "") {
                if (pre === this.StartEventId)
                  inputCopy[j] =
                    "${workflow.input." +
                    inputCopy[j][0] +
                    inputCopy[j][1] +
                    "}";
                else
                  inputCopy[j] =
                    "${" +
                    this.Form[pre].description +
                    ".output." +
                    inputCopy[j][0] +
                    inputCopy[j][1] +
                    "}";
              } else delete inputCopy[j];
            }
            t.inputParameters = Object.assign({}, t.inputParameters, inputCopy);
          }
        }
        tasks_tmp.push(t);
      }
      let maps = {};
      let endEvent = elementRegistry.get(this.EndEventId);
      for (let i = 0; i < endEvent.incoming.length; ++i) {
        let sequenceFlow = endEvent.incoming[i];
        let outputCopy = Object.assign({}, this.Form[sequenceFlow.id].maps);
        let pre = sequenceFlow.source.id;
        for (let j in outputCopy) {
          if (outputCopy[j] != null && outputCopy[j][0] != "") {
            outputCopy[j] =
              "${" +
              this.Form[pre].description +
              ".output." +
              outputCopy[j][0] +
              outputCopy[j][1] +
              "}";
          } else delete outputCopy[j];
        }
        maps = Object.assign({}, maps, outputCopy);
      }
      let Process_tmp = {
        ...this.Form.Process,
        tasks: tasks_tmp,
        outputParameters: maps,
        inputParameters: this.Form[this.StartEventId].outputKeys
      };
      this.Form.Process = Process_tmp;
    },
    updateRelatedSequenceFlow(k) {
      let elementRegistry = this.bpmnModeler.get("elementRegistry");
      if (k === "outputKeys") {
        console.log("outputKeys");
        let startEvent = elementRegistry.get(this.StartEventId);
        console.log("处理后面的sequenceFlow");
        for (let i = 0; i < startEvent.outgoing.length; ++i) {
          let sequenceFlow = startEvent.outgoing[i];
          if (sequenceFlow.id in this.Form) {
            let maps = {};
            for (let i in this.Form[sequenceFlow.id].maps) {
              maps[i] = ["", ""];
            }
            this.Form[sequenceFlow.id] = {
              ...this.Form[sequenceFlow.id],
              maps: maps,
              values: this.Form[this.StartEventId].outputKeys
            };
          }
        }
      } else if (k === "inputKeys") {
        console.log("inputKeys");
        let endEvent = elementRegistry.get(this.EndEventId);
        for (let i = 0; i < endEvent.incoming.length; ++i) {
          console.log("处理前面的sequenceFlow");
          let sequenceFlow = endEvent.incoming[i];
          if (sequenceFlow.id in this.Form) {
            let maps = {};
            for (
              let i = 0;
              i < this.Form[this.EndEventId].inputKeys.length;
              ++i
            ) {
              maps[this.Form[this.EndEventId].inputKeys[i]] = ["", ""];
            }
            this.Form[sequenceFlow.id].maps = maps;
          }
        }
      }
    },
    submit() {
      alert("submit");
      let tasksJson = [];
      for (let i = 0; i < this.TaskList.length; ++i) {
        let task = Object.assign({}, this.Form[this.TaskList[i]]);
        console.log("task", task);
        for (let k in task) {
          if (task[k] === null || task[k] === "") delete task[k];
        }
        delete task.type;
        tasksJson.push(task);
      }
      console.log("tasksJson", tasksJson);
      let workflowJson = [];
      let process = Object.assign({}, this.Form.Process);
      for (let k in process) {
        if (process[k] === null || process[k] === "") delete process[k];
      }
      delete process.type;
      workflowJson.push(process);
      console.log("workflowJson", workflowJson);
      this.$http
        .post("http://192.168.12.106:8080/api/metadata/taskdefs", tasksJson)
        .then(r => alert("tasks submit success!", r))
        .catch(err => alert(err));
      this.$http
        .put("http://192.168.12.106:8080/api/metadata/workflow", workflowJson)
        .then(r => alert("process submit success!!", r))
        .catch(err => alert(err));
    }
  },
  mounted() {
    // 获取到属性ref为“content”的dom节点
    this.container = this.$refs.content;
    // 获取到属性ref为“canvas”的dom节点
    const canvas = this.$refs.canvas;

    // 建模，官方文档这里讲的很详细
    this.bpmnModeler = new BpmnModeler({
      container: canvas,
      // 添加控制板
      // propertiesPanel: {
      //   parent: "#js-properties-panel"
      // },
      // modules: [coreModule, modelingModule],
      additionalModules: [
        // 左边工具栏以及节点
        propertiesProviderModule
        // 右边的工具栏
        // propertiesPanelModule
      ]
      // moddleExtensions: {
      //   camunda: camundaModdle
      // }
    });
    this.Form["Process"] = {
      type: "Process",
      name: "Process_name",
      description: "a description of process",
      version: 1,
      tasks: [],
      inputParameters: [],
      outputParameters: {},
      failureWorkflow: "",
      restartable: true,
      workflowStatusListenerEnabled: true,
      schemaVersion: 2
    };

    // 下载画图
    let _this = this;
    // 获取a标签dom节点
    const downloadLink = this.$refs.saveDiagram;
    const downloadSvgLink = this.$refs.saveSvg;
    // 给图绑定事件，当图有发生改变就会触发这个事件
    this.bpmnModeler.on("commandStack.changed", function(e) {
      _this.saveSVG(function(err, svg) {
        _this.setEncoded(downloadSvgLink, "diagram.svg", err ? null : svg);
      });

      _this.saveDiagram(function(err, xml) {
        _this.setEncoded(downloadLink, "diagram.bpmn", err ? null : xml);
      });
    });
    this.bpmnModeler.on("selection.changed", res => {
      console.log("selection", res);
      console.log("Form", _this.Form);
      if (res.newSelection.length > 0) {
        let index = 0;
        while (
          index < res.newSelection.length &&
          !(res.newSelection[index].businessObject.$type in _this.ElementType)
        ) {
          ++index;
        }
        console.log(res.newSelection[index].businessObject.$type);

        if (index < res.newSelection.length) {
          _this.CurrentElement.id = res.newSelection[index].businessObject.id;
          _this.CurrentElement.type =
            res.newSelection[index].businessObject.$type;

          console.log("before Create new Stuff ", _this.Form);
          if (
            res.newSelection[index].businessObject.$type === "bpmn:Task" &&
            !(_this.CurrentElement.id in _this.Form)
          ) {
            _this.TaskList.push(_this.CurrentElement.id);
            _this.CurrentElement.name =
              res.newSelection[index].businessObject.name;
            _this.Form[_this.CurrentElement.id] = {
              name: _this.CurrentElement.name,
              description: "",
              retryCount: 3,
              retryLogic: "FIXED",
              retryDelaySeconds: 60,
              timeoutPolicy: "RETRY",
              timeoutSeconds: 3600,
              responseTimeoutSeconds: 3600,
              inputKeys: [],
              outputKeys: [],
              inputTemplate: "",
              concurrentExecLimit: "",
              rateLimitFrequencyInSeconds: "",
              type: "bpmn:Task"
            };
            console.log("After Creation ", _this.Form);
          } else if (
            res.newSelection[index].businessObject.$type ===
              "bpmn:StartEvent" &&
            !(_this.CurrentElement.id in _this.Form)
          ) {
            _this.StartEventId = _this.CurrentElement.id;
            _this.Form[_this.CurrentElement.id] = {
              type: "bpmn:StartEvent",
              outputKeys: []
            };
          } else if (
            res.newSelection[index].businessObject.$type === "bpmn:EndEvent" &&
            !(_this.CurrentElement.id in _this.Form)
          ) {
            _this.EndEventId = _this.CurrentElement.id;
            _this.Form[_this.CurrentElement.id] = {
              type: "bpmn:EndEvent",
              inputKeys: []
            };
          } else if (
            res.newSelection[index].businessObject.$type ===
              "bpmn:SequenceFlow" &&
            !(_this.CurrentElement.id in _this.Form)
          ) {
            _this.SequenceFlowList.push(_this.CurrentElement.id);
            let s = res.newSelection[index].source.id;
            let t = res.newSelection[index].target.id;
            _this.Form[_this.CurrentElement.id] = {
              type: "bpmn:SequenceFlow",
              id: _this.CurrentElement.id,
              source: s,
              target: t,
              maps: {},
              values: _this.Form[s].outputKeys
            };
            console.log("inputKeys", _this.Form[t].inputKeys);
            let maps = {};
            for (let i = 0; i < _this.Form[t].inputKeys.length; ++i)
              maps[_this.Form[t].inputKeys[i]] = ["", ""];
            _this.Form[_this.CurrentElement.id].maps = maps;
          }
          console.log("FForm", _this.Form);
        }
      } else {
        _this.CurrentElement.id = "Process";
        _this.CurrentElement.type = "Process";
      }
    });
    this.createNewDiagram(this.bpmnModeler);
  }
};
</script>

<style lang="scss">
/*左边工具栏以及编辑节点的样式*/
@import "bpmn-js/dist/assets/diagram-js.css";
@import "bpmn-js/dist/assets/bpmn-font/css/bpmn.css";
@import "bpmn-js/dist/assets/bpmn-font/css/bpmn-codes.css";
@import "bpmn-js/dist/assets/bpmn-font/css/bpmn-embedded.css";
/*右边工具栏样式*/
// @import "bpmn-js-properties-panel/dist/assets/bpmn-js-properties-panel.css";
.containers {
  position: absolute;
  background-color: #ffffff;
  width: 100%;
  height: 90%;
}
.canvas {
  width: 100%;
  height: 100%;
}
.panel {
  position: absolute;
  width: 400px;
  right: 10px;
  top: 200px;
}
.buttons {
  position: absolute;
  left: 100px;
  bottom: 0px;
  & > li {
    display: inline-block;
    margin: 5px;
    & > a {
      color: #999;
      background: #eee;
      cursor: not-allowed;
      padding: 8px;
      border: 1px solid #ccc;
      &.active {
        color: #333;
        background: #fff;
        cursor: pointer;
      }
    }
  }
}
</style>
